
package vu.cs.heuristieken;

import java.util.List;
import java.util.LinkedList;
import java.util.ListIterator;

public class Field extends ContainerEntity {
    protected CellType[][] cells;

    public Field(Size size) {
        super(size);
        this.cells  = new CellType[this.getWidth() + 10][this.getDepth()];
        for(int x = 0; this.getWidth() > x; x++) {
            for(int y = 0; this.getDepth() > y; y++) {
                this.cells[x][y] = CellType.CELLTYPE_EMPTY;
            }
        }
    }

    public Field(Size size, List<Placement> placements) {
        this(size);
        for(Placement placement : placements) {
            this.place(placement);
        }
    }

    public boolean place(Placement placement) {
        if((null != placement)
        && (0 <= placement.getPosition().getX()) && (placement.getPosition().getX() < this.getWidth())
        && (0 <= placement.getPosition().getY()) && (placement.getPosition().getY() < this.getDepth())) {
            this._fillCells(placement);
            this.addPlacement(placement);
            return true;
        }
        return false;
    }

    private void _fillCells(Placement placement) {
        int x         = placement.getPosition().getX();
        int y         = placement.getPosition().getY();
        Entity entity = placement.getEntity();

        if(entity instanceof House) {
            House house = (House) entity;
            this._fillRectangle(Math.max(0, x - house.getVrijstand()),
                                Math.max(0, y - house.getVrijstand()),
                                Math.min(this.getWidth(), x + house.getWidth() + house.getVrijstand()) - 1,
                                Math.min(this.getDepth(), y + house.getDepth() + house.getVrijstand()) - 1,
                                CellType.CELLTYPE_VRIJSTAND);
            this._fillRectangle(x,
                                y,
                                x + entity.getWidth() - 1,
                                y + entity.getDepth() - 1,
                                CellType.CELLTYPE_HOUSE);
            return;
        }
        else if(entity instanceof Column) {
            Column column         = (Column) entity;
            int _y                = 0;
            for(Placement p : column.getPlacements()) {
                this._fillCells(new Placement(p.getEntity(), new Position(x, _y)));
                if(p.getEntity() instanceof House) {
                    House house = (House) p.getEntity();
                    _y += house.getDepth() + house.getVrijstand();
                }
                else {
                    _y += p.getEntity().getDepth();
                }
            }
        }
        else if(entity instanceof Field) {
            Field field = (Field) entity;
            for(int _x = 0; field.getWidth() > x; x++) {
                for(int _y = 0; field.getDepth() > y; y++) {
                    this.cells[x + _x][y + _y] = field.getCellType(x, y);
                }
            }
        }
        else if(entity instanceof Lake) {
            this._fillRectangle(x,
                                y,
                                x + entity.getWidth() - 1,
                                y + entity.getDepth() - 1,
                                CellType.CELLTYPE_WATER);
        }
    }

    private void _fillRectangle(int startX, int startY, int endX, int endY, CellType cellType) {
        for(int x = startX; endX >= x; x++) {
            for(int y = startY; endY >= y; y++) {
                this.cells[x][y] = cellType;
            }
        }
    }

    public CellType getCellType(int x, int y) {
        return this.cells[x][y];
    }

    public void setCellType(int x, int y, CellType cellType) {
        this.cells[x][y] = cellType;
    }

    public void reserveSubfield(int startX, int startY, int endX, int endY) {
        this._fillRectangle(startX, startY, endX, endY, CellType.CELLTYPE_RESERVED);
    }

    public Field getEmptySubfield(int startX, int startY, int endX, int endY) {
        Field result = new Field(new Size((endX - startX) + 1, (endY - startY) + 1));
        // TODO: fill the cells.
        return result;
    }

    public Field clone() 
        throws CloneNotSupportedException {
        Field clone = (Field) super.clone();
        
        clone.cells = new CellType[this.getWidth()][this.getDepth()];
        for(int x = 0; this.getWidth() > x; x++) {
            for(int y = 0; this.getDepth() > y; y++) {
                clone.cells[x][y] = this.cells[x][y];
            }
        }
        return clone;
    }
}
